package de.lgohlke.helper;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import de.lgohlke.helper.CompressionHelper.Reader;
import de.lgohlke.helper.CompressionHelper.StreamReader;
import de.lgohlke.helper.CompressionHelper.StreamWriter;
import de.lgohlke.helper.CompressionHelper.Writer;

/**
 * <p>FileHelper class.</p>
 *
 * @author lars
 * @version $Id: $
 */
public class FileHelper
{
  private final static Logger log = LoggerFactory.getLogger(FileHelper.class);

  public static enum TYPE
  {
    // BZIP,
    GZIP, DEFLATE
  }

  public static enum DIRECTION
  {
    COMPRESS, UNCOMPRESS
  }

  private final TYPE type = TYPE.GZIP;
  private boolean    deleteAfterConverstion;

  public static class RawFileReader extends Reader
  {
    public RawFileReader(final FileInputStream src) throws IOException
    {
      setStream(src);
    }
  }

  public static class RawFileWriter extends Writer
  {
    public RawFileWriter(final OutputStream destination) throws IOException
    {
      setStream(destination);
    }
  }

  /**
   * <p>convertFile.</p>
   *
   * @param source a {@link java.io.File} object.
   * @param destination a {@link java.io.File} object.
   * @param direction a {@link de.lgohlke.helper.FileHelper.DIRECTION} object.
   * @throws java.io.IOException if any.
   */
  public void convertFile(final File source, final File destination, final DIRECTION direction) throws IOException
  {
    { // precheck
      if (!source.exists())
      {
        throw new IOException("source file doesnt exist:" + source.getAbsolutePath());
      }

      if (source.getAbsoluteFile().toString().equals(destination.getAbsoluteFile().toString()))
      {
        throw new IOException("source and destination must be different");
      }
    }
    {
      StreamWriter writer;
      StreamReader reader;

      if (direction.equals(DIRECTION.COMPRESS))
      {
        reader = new RawFileReader(new FileInputStream(source));

        // writer = new BZIP2Writer(new FileOutputStream(destination), buffSize);
        writer = new CompressionHelper.GZIPWriter(new FileOutputStream(destination));
        // writer = new LzmaWriter(new FileOutputStream(destination), buffSize);
      }
      else
      {
        // reader = new BZIP2Reader(new FileInputStream(source), buffSize);
        reader = new CompressionHelper.GZIPReader(new FileInputStream(source));
        // reader = new LzmaReader(new FileInputStream(source), buffSize);
        writer = new RawFileWriter(new FileOutputStream(destination));
      }

      log.error("starting to " + direction + " with " + type + " " + source.getAbsolutePath() + " ... ");
      CompressionHelper.convertStream(writer, reader);
      log.error("fertig");
    }

    {
      // postcheck
      if (deleteAfterConverstion && source.exists())
      {
        source.delete();
      }
    }

  }

  /**
   * <p>compressFile.</p>
   *
   * @param source a {@link java.io.File} object.
   * @param destination a {@link java.io.File} object.
   * @throws java.io.IOException if any.
   */
  public void compressFile(final File source, final File destination) throws IOException
  {
    convertFile(source, destination, DIRECTION.COMPRESS);
  }

  /**
   * <p>uncompressFile.</p>
   *
   * @param source a {@link java.io.File} object.
   * @param destination a {@link java.io.File} object.
   * @throws java.io.IOException if any.
   */
  public void uncompressFile(final File source, final File destination) throws IOException
  {
    convertFile(source, destination, DIRECTION.UNCOMPRESS);
  }

  /**
   * <p>setDeleteAfterConversion.</p>
   *
   * @param b a boolean.
   */
  public void setDeleteAfterConversion(final boolean b)
  {
    deleteAfterConverstion = b;
  }

  /**
   * <p>writeStringToFileCompressed.</p>
   *
   * @param fileCompressed a {@link java.io.File} object.
   * @param data a {@link java.lang.String} object.
   * @throws java.io.IOException if any.
   */
  public static void writeStringToFileCompressed(final File fileCompressed, final String data) throws IOException
  {
    writeToFileCompressed(fileCompressed, data.getBytes());
  }

  /**
   * <p>writeToFileCompressed.</p>
   *
   * @param fileCompressed a {@link java.io.File} object.
   * @param data an array of byte.
   * @throws java.io.IOException if any.
   */
  public static void writeToFileCompressed(final File fileCompressed, final byte[] data) throws IOException
  {
    byte[] compressed = CompressionHelper.compress(data).type(CompressionHelper.TYPE.GZIP).getBytes();
    FileUtils.writeByteArrayToFile(fileCompressed, compressed);
  }

  /**
   * <p>readStringFromFileCompressed.</p>
   *
   * @param fileCompressed a {@link java.io.File} object.
   * @return a {@link java.lang.String} object.
   * @throws java.io.IOException if any.
   */
  public static String readStringFromFileCompressed(final File fileCompressed) throws IOException
  {
    return new String(readFromFileCompressed(fileCompressed));
  }

  /**
   * <p>readFromFileCompressed.</p>
   *
   * @param fileCompressed a {@link java.io.File} object.
   * @return an array of byte.
   * @throws java.io.IOException if any.
   */
  public static byte[] readFromFileCompressed(final File fileCompressed) throws IOException
  {
    byte[] data = FileUtils.readFileToByteArray(fileCompressed);
    return CompressionHelper.uncompress(data).type(CompressionHelper.TYPE.GZIP).getBytes();
  }
}
